package com.shell.governor.authorization.service.impl;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.shell.bee.base.utils.SpringContextUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.entity.mvc.RetMsg;
import com.shell.bee.persistence.service.impl.PersistentServiceImpl;
import com.shell.bee.persistence.utils.EntityUtil;
import com.shell.constant.ind.PubConstants;
import com.shell.feign.ContractTransferFeigh;
import com.shell.framework.utils.CommonDataUtil;
import com.shell.framework.utils.SysDateUtil;
import com.shell.governor.authorization.UserRoleEvent;
import com.shell.governor.authorization.dao.PubResourceDao;
import com.shell.governor.authorization.dao.PubRoleDao;
import com.shell.governor.authorization.dao.PubRoleResourceDao;
import com.shell.governor.authorization.dao.PubUserResourceExcDao;
import com.shell.governor.authorization.po.PubResource;
import com.shell.governor.authorization.po.PubRole;
import com.shell.governor.authorization.po.PubRoleResource;
import com.shell.governor.authorization.po.PubUserResourceExc;
import com.shell.governor.authorization.rx.AuthRoleMsgSubscriber;
import com.shell.governor.authorization.service.PubResourceService;
import com.shell.governor.modules.dao.PubApplicationDao;
import com.shell.governor.modules.po.PubApplication;
import com.shell.governor.modules.service.PubApplicationService;
import com.shell.governor.user.dao.PubUserRoleDao;
import com.shell.governor.user.po.PubUserRole;

import rx.Observable;
import tk.mybatis.mapper.entity.Example;

@Service
public class PubResourceServiceImpl extends PersistentServiceImpl<PubResource> implements PubResourceService {
	@Autowired
	PubResourceDao pubResourceDao;
	@Autowired
	PubRoleResourceDao pubRoleResourceDao;
	@Autowired
	PubUserRoleDao pubUserRoleDao;
	@Autowired
	PubUserResourceExcDao pubUserResourceExcDao;
	@Autowired
	PubApplicationDao pubApplicationDao;
	@Autowired
	PubApplicationService pubApplicationService;
	@Autowired
	PubRoleDao pubRoleDao;
	@Autowired
	private ContractTransferFeigh contractTransferFeigh;
	@Autowired
	private AuthRoleMsgSubscriber authRoleMsgSubscriber;

	public int saveOrUpdateResource(PubResource res) {
		if (StringUtil.notTrimEmpty(res.getResId())) {
			res.setEditorId(CommonDataUtil.getUserId());
			res.setEditTime(SysDateUtil.getSystemDateTime());
			return updateAll(res);
		}
		String resId = SystemUtil.getUUID();
		res.setResId(resId);
		res.setResPath(res.getResPath() + ',' + res.getResId());
		res.setCreateTime(SysDateUtil.getSystemDateTime());
		res.setCreatorId(CommonDataUtil.getUserId());

		int i = save(res);

		return i;
	}

	public List<PubResource> selectResourceTree(PubResource resource) {
		if (!StringUtil.emptyAndNull(resource.getResName())) {
			resource.setResName(StringUtil.getParameterLike(resource.getResName()));
		}
		List<PubResource> resources = this.pubResourceDao.selectResourceTree(resource);
		for (PubResource res : resources) {
			if (!StringUtil.emptyAndNull(res.getResPath())) {
				String[] id = res.getResPath().split(",");
				String parentName = "";
				if (id.length > 2) {
					for (int i = 1; i < id.length; i++) {
						PubResource parentRes = (PubResource) this.pubResourceDao.selectByPrimaryKey(id[i]);
						if (parentRes == null) {
							this.logger
									.info(res.getResName() + ":" + res.getResPath() + "����ID" + id[i] + "����������");
						} else {
							parentName = parentName + parentRes.getResName() + "_";
						}
					}
				}
				res.setParentName(parentName);
			}
		}
		List<PubResource> resTreeList = new ArrayList<PubResource>();
		genSubResourceTree(resources, new ArrayList<PubResource>(), 0, 0);
		return resTreeList;
	}

	private int genSubResourceTree(List<PubResource> resources, List<PubResource> children, int start, int level) {
		int index = start;
		while (index < resources.size()) {
			PubResource res = (PubResource) resources.get(index);
			if (res.getResLevel().intValue() == level) {
				children.add(res);
				res.setChildren(new ArrayList<PubResource>());
				index = genSubResourceTree(resources, res.getChildren(), index + 1, level + 1);
			} else {
				if (res.getResLevel().intValue() < level) {
					break;
				}
				if (res.getResLevel().intValue() > level) {
					index = genSubResourceTree(resources, children, index, res.getResLevel().intValue());
				}
			}
		}
		if (children.size() > 0) {
			Collections.sort(children, new Comparator<PubResource>() {
				@Override
				public int compare(PubResource arg0, PubResource arg1) {
					if ((arg0.getResSort() == null) && (arg1.getResSort() == null)) {
						return 0;
					}
					if (arg0.getResSort() == null) {
						return 1;
					}
					if (arg1.getResSort() == null) {
						return -1;
					}
					return arg0.getResSort().compareTo(arg1.getResSort());
				}

			});
		}
		return index;
	}

	public PubResource findResourceByResId(String resId) {
		PubResource res = (PubResource) selectByKey(resId);
		if ((res.getResLevel().intValue() > 0) && (!StringUtil.emptyAndNull(res.getParentId()))) {
			PubResource pubResource = (PubResource) selectByKey(res.getParentId());
			if (pubResource != null) {
				res.setParentName(pubResource.getResName());
			}
		}
		return res;
	}

	public int updateResourceStateWithCascade(String resId, String resState) {
		if (resState.equals("E")) {
			PubResource res = (PubResource) this.pubResourceDao.selectByPrimaryKey(resId);
			if (StringUtil.notTrimEmpty(res.getResPath())) {
				String[] ids = res.getResPath().split(",");
				for (String id : ids) {
					if ((!StringUtil.empty(id)) && (!id.equals(resId))) {
						PubResource pRes = new PubResource();
						pRes.setResId(id);
						pRes.setResState(resState);
						updateNotNull(pRes);
					}
				}
			}
		}
		return this.pubResourceDao.updateResourceStateWithCascade("%" + resId + "%", resState);
	}

	public boolean checkCodeUnique(PubResource resource) {
		if (StringUtil.trimEmpty(resource.getResCode())) {
			return true;
		}
		Example example = new Example(PubResource.class);
		Example.Criteria criteria = example.createCriteria();
		if (!StringUtil.trimEmpty(resource.getResId())) {
			criteria.andNotEqualTo("resId", resource.getResId());
		}
		criteria.andEqualTo("resCode", resource.getResCode());
		criteria.andNotEqualTo("resState", "D");

		List<PubResource> list = selectByExample(example);
		if (list.size() > 0) {
			return false;
		}
		return true;
	}

	public InputStream genSql(String id) throws Exception {
		PubResource res = (PubResource) selectByKey(id);
		StringBuilder sb = new StringBuilder();
		sb.append("/* ��������[").append(res.getResName()).append("]*/\r\n");
		sb.append(EntityUtil.genInsertSql(res)).append(";\r\n");
		List<PubRoleResource> rrs = this.pubRoleResourceDao.selectResAndRoleByResId(id);
		for (PubRoleResource rr : rrs) {
			sb.append("/* ������[").append(res.getResName()).append("]��������[").append(rr.getRoleName())
					.append("]*/\r\n");
			sb.append(EntityUtil.genInsertSql(rr)).append(";\r\n");
		}
		ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes());
		return is;
	}

	public int deleteResourceWithCascade(PubResource resource) {
		if (StringUtil.notEmpty(resource.getParentId())) {
			PubResource tempResource = new PubResource();
			tempResource.setParentId(resource.getParentId());
			List<PubResource> ress = selectByEntity(tempResource);
			if ((ress != null) && (ress.size() == 1)) {
				PubResource parentResource = new PubResource();
				parentResource.setResId(resource.getParentId());
				updateNotNull(parentResource);
			}
		}
		return this.pubResourceDao.deleteResourceWithCascade("%," + resource.getResId() + "%");
	}

	public List<PubResource> selectResourceTree4Role(String roleId) throws Exception {
		String type = "1";
		PubRole role = (PubRole) this.pubRoleDao.selectByPrimaryKey(roleId);
		List<PubResource> resources = this.pubResourceDao.selectRoleResourceTree(role.getAppId(),
				CommonDataUtil.getUserId(), roleId, type);
		List<PubResource> resTreeList = new ArrayList<PubResource>();
		genSubResourceTree(resources, resTreeList, 0, 0);
		return resTreeList;
	}

	public RetMsg authResourceToRole(String roleId, String resIds, String type) {
		if (!StringUtil.trimEmpty(roleId)) {
			this.pubRoleResourceDao.deleteRoleRResourceByRoleId(roleId, type);
			if (!StringUtil.trimEmpty(resIds)) {
				String[] resIdArr = resIds.split(",");
				for (String resId : resIdArr) {
					if (StringUtil.notTrimEmpty(resId)) {
						PubRoleResource roleRResource = new PubRoleResource();
						roleRResource.setResId(resId);
						roleRResource.setRoleId(roleId);
						roleRResource.setRoleResType(type);
						this.pubRoleResourceDao.insert(roleRResource);
					}
				}
			}
		} else {
			return new RetMsg("error", "����������");
		}
		return new RetMsg("success", "��������");
	}

	public List<PubResource> selectResourceTree4User(String roleIds, String userId, String entId, String appId)
			throws Exception {
		Map<String, String> nameValueMap = (Map) SystemUtil.getConstantsNameValueMap(PubConstants.class)
				.get("TerminalCode");
		Map<String, String> valueMap = (Map) SystemUtil.getConstantsValueMap(PubConstants.class).get("TerminalCode");
		List<PubResource> ress = new ArrayList<PubResource>();
		String[] appIds = appId.split(",");
		Set<String> appIdSet = new HashSet<String>();
		appIdSet.addAll(Arrays.asList(appIds));
		List<PubApplication> apps = this.pubApplicationService.getApplication(null);
		PubApplication application;
		PubResource appRes;
		List<PubResource> appRess;
		for (Iterator<PubApplication> localIterator1 = apps.iterator(); localIterator1.hasNext();) {
			application = (PubApplication) localIterator1.next();

			appRes = new PubResource();
			appRes.setResId(application.getAppCode());
			appRes.setResName(application.getAppName());
			appRess = new ArrayList<PubResource>();
			for (String key : nameValueMap.keySet()) {
				if (!"current".equals(key)) {
					PubResource res = new PubResource();
					res.setResId((String) nameValueMap.get(key) + "_" + application.getAppId());
					res.setResName((String) valueMap.get(nameValueMap.get(key)));
					List<PubResource> resources = this.pubResourceDao.selectResourceTree4User(roleIds.split(","),
							userId, entId, application.getAppId(), (String) nameValueMap.get(key));
					List<PubResource> resTreeList = new ArrayList<PubResource>();
					if ((resources != null) && (resources.size() > 0)) {
						genSubResourceTree(resources, resTreeList, 0, 0);
						for (PubResource firstRes : resTreeList) {
							firstRes.setParentId(res.getResId());
							if (firstRes.isChecked()) {
								res.setChecked(true);
								appRes.setChecked(true);
							}
						}
						res.setChildren(resTreeList);
						res.setParentId(application.getAppCode());
						appRess.add(res);
					}
					if ((appRess != null) && (appRess.size() > 0)) {
						appRes.setChildren(appRess);
						ress.add(appRes);
					}
				}
			}
		}
		return ress;
	}

	public RetMsg authResourceToUser(String userId, String roleIds, String resIds, String organId) {
		PubUserRole ur = new PubUserRole();
		ur.setUserId(userId);
		ur.setOrganId(organId);
		this.pubUserRoleDao.delete(ur);

		PubUserResourceExc ure = new PubUserResourceExc();
		ure.setUserId(userId);
		this.pubUserResourceExcDao.delete(ure);
		if (!StringUtil.emptyAndNull(roleIds)) {
			String[] roleIdArr = roleIds.split(",");
			for (String roleId : roleIdArr) {
				PubUserRole userRole = new PubUserRole();
				userRole.setOrganId(organId);
				userRole.setRoleId(roleId);
				userRole.setUserId(userId);
				this.pubUserRoleDao.insert(userRole);

				UserRoleEvent event = new UserRoleEvent();
				event.setPubUserRole(userRole);
				Observable<UserRoleEvent> observers = Observable.just(event);
				observers.subscribe(this.authRoleMsgSubscriber);
			}
			if ("on".equals(SpringContextUtil.getProperty("contract.switch"))) {
				this.contractTransferFeigh.signerActiveSync(organId, userId);
			}
		}
		if (!StringUtil.emptyAndNull(resIds)) {
			String[] resIdArr = resIds.split(",");
			for (String resId : resIdArr) {
				PubUserResourceExc userResourceExc = new PubUserResourceExc();
				userResourceExc.setOrganId(organId);
				userResourceExc.setResId(resId);
				userResourceExc.setUserId(userId);
				this.pubUserResourceExcDao.insert(userResourceExc);
			}
		}
		return new RetMsg("success", "����������");
	}

	public List<PubResource> selectAllResourceTree4User(String userId, String entId, String trmlCode, String appId) {
		List<PubResource> resources = this.pubResourceDao.selectAllResource4User(userId, entId, trmlCode, appId);
		List<PubResource> resTreeList = new ArrayList<PubResource>();
		genSubResourceTree(resources, resTreeList, 0, 0);
		return resTreeList;
	}
}